package org.bpm
{
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IEventDispatcher;
	import flash.filters.DropShadowFilter;
	import flash.sampler.NewObjectSample;
	
	import org.bpm.events.*;
	import org.bpm.models.MapModel;
	import org.bpm.operation.XMLOperation;
	import org.bpm.utils.UIManifest;
	import org.bpm.view.Map;
	
	/**
	 * @author, James Li;
	 * version 1.0
	 * 
	 * This library provides funtionality of display a map which generated via JBPM,
	 * by loading gpd.xml and processdefinition.xml you can create a map with flash for better display.
	 * 
	 * *** YOU HAVE TO indicate different names in the JBPM for each node, because it's the unique id here.
	 * 
	 * what is available:
	 * 
	 * 1, display start-state, end-state, fork, join, decision, node, task-node, node, and transition lines in two status.
	 * 2, you can skin the node views in assets/flash/ui.fla
	 * 3, you can extend the mouse event behaviors via adding listeners to catch ProcessMapEvent
	 * 4, pure actionscript library, is available for action script projects.
	 * 
	 * what is not available:
	 * 
	 * 1, curve lines and none-straight lines display.
	 * 2, actions and original interactions of bpm.
	 * 3, default mouse behaviors.
	 * 
	 * 
	 * 2011-1-21;
	 * http://jamesli.cn/blog;
	 * */
	public class ProcessMap extends Sprite
	{
		
		
		private var gpdXML:XMLList;
		private var map:Map;
		private var xo:XMLOperation;
		private var isKilled:Boolean;
		
		public function ProcessMap()
		{
			super();
			/**Refer ui skins that might use in the map*/
			new UIManifest();
			
			addEventListener(Event.REMOVED_FROM_STAGE, onRemoveFromStage);
		}
		
		override public function set width(value:Number):void{
			/**/
		}
		override public function set height(value:Number):void{
			/**/
		}
		override public function get width():Number{
			return map ? map.width : 0;
		}
		override public function get height():Number{
			return map ? map.height : 0;
		}
		
		/**
		 * If xml files are external.
		 * */
		
		public function loadAndConfigMap(pGPDXMLUrl:String,pPDXMLUrl:String):void{
			xo = new XMLOperation(pGPDXMLUrl,pPDXMLUrl);
			xo.addEventListener(XMLOperationEvent.XML_READY, xmlReadyHandler);
		}
		private function xmlReadyHandler(pEvent:XMLOperationEvent):void{
			if(xo){
				xo.removeEventListener(XMLOperationEvent.XML_READY, xmlReadyHandler);
				xo = null;
			}
			if(map){
				updateMap(pEvent.params[0]);
			}else{
				configMap(pEvent.params[0],pEvent.params[1]);				
			}
		}
		
		/**
		 * This method can be involved if the xml was generated by other application already, without loading.
		 * */
		public function configMap(pGPDXML:XMLList,pPDXML:XMLList):void{
			if(isKilled) return;
			
			gpdXML = pGPDXML;
			
			createMap(pGPDXML,pPDXML);
			
			dispatchEvent(new ProcessMapEvent(ProcessMapEvent.MAP_CONFIG_COMPLETE));
		}
		
		/**
		 * Load the updated processdefinition.xml, which should has process status information and interactive information.
		 * */
		public function loadAndUpdateMap(pUpdateXMLUrl:String):void{
			xo = new XMLOperation(pUpdateXMLUrl);
			xo.addEventListener(XMLOperationEvent.XML_READY,xmlReadyHandler);
		}
		
		/**
		 * This method can be involved directly if status xml is not from external.
		 * */
		public function updateMap(pUpdateXML:XMLList):void{
			removeMap();
			createMap(gpdXML,pUpdateXML);
			dispatchEvent(new ProcessMapEvent(ProcessMapEvent.MAP_UPDATE_COMPLETE));
		}
		
		private function onRemoveFromStage(pEvent:Event):void{
			removeEventListener(Event.REMOVED_FROM_STAGE, onRemoveFromStage);
			isKilled = true;
			
			removeMap();
			
			if(xo){
				xo.removeEventListener(XMLOperationEvent.XML_READY, xmlReadyHandler);
				xo = null;
			}
			gpdXML = null;
		}
		private function createMap(pGPDXML:XMLList,pPDXML:XMLList):void{
			map = new Map(new MapModel(pGPDXML, pPDXML));
			addChild(map);
			map.addEventListener(ProcessMapEvent.MAP_ELEMENT_OVER, mouseEvent);
			map.addEventListener(ProcessMapEvent.MAP_ELEMENT_OUT, mouseEvent);
			map.addEventListener(ProcessMapEvent.MAP_ELEMENT_CLICK, mouseEvent);
		}
		private function mouseEvent(pEvent:ProcessMapEvent):void{
			dispatchEvent(pEvent.clone());
		}
		private function removeMap():void{
			if(map){
				removeChild(map);
				map.removeEventListener(ProcessMapEvent.MAP_ELEMENT_OVER, mouseEvent);
				map.removeEventListener(ProcessMapEvent.MAP_ELEMENT_OUT, mouseEvent);
				map.removeEventListener(ProcessMapEvent.MAP_ELEMENT_CLICK, mouseEvent);
				map = null;
			}
		}
		
	}
}